#ifndef _THREADPOOL_H__
#define _THREADPOOL_H__

#include <vector>
#include <queue>
#include <memory>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <unordered_map>

class Any
{
public:
    Any() = default;
    Any(const Any&) = delete;
    Any& operator=(const Any&) = delete;
    Any(Any&&) = default;
    Any& operator=(Any&&) = default;
    ~Any() = default;

    // 动态接收任意类型元素并且存储
    template <typename T>
    Any(T data):base_(std::make_unique<Drive<T>>(data))
    {
    }

    //将任意类型元素，转换为具体元素并返回。
    template <typename T>
    T cast_()
    {
        //首先将基类指针的裸指针拿到，然后dynamic_cast进行强制转换为派生类指针，然后去派生类下拿数据，进行返回。
        Drive<T>* drive_ptr = dynamic_cast<Drive<T>*>(base_.get());
        if(drive_ptr == nullptr)
        {
            throw "type is unmatch";
        }
        return drive_ptr->data_;
    }

public:
    //基类类型
    class Base
    {
    public:
        virtual ~Base() = default;
    };

    //派生类类型
    template <typename T>
    class Drive : public Base
    {
    public:
        T data_;
    public:
        Drive(T data):data_(data)
        {
        }
    };
private:
    std::unique_ptr<Base> base_;
};

//实现一个信号量类
class Semapthore
{
public:
    Semapthore(int limit_ = 0)
    :ref_limit_(limit_)
    {

    }
    ~Semapthore() = default;
    //信号量减1，如果没有信号量了就等待
    void wait()
    {
        std::unique_lock<std::mutex> lock(mtx_);
        con_.wait(lock,[this](){return ref_limit_ != 0;});
        ref_limit_--;
    }
    //信号量加一
    void post()
    {
        std::lock_guard<std::mutex> lock(mtx_);
        ref_limit_++;
        con_.notify_all();
    }
private:
    int ref_limit_;
    std::mutex mtx_;
    std::condition_variable con_;
};
class Task;
class Result
{
    //目的是用户调用该类获取线程执行结果，如果有执行结果就返回，如果没有执行结果就等待。
public:
    Result(std::shared_ptr<Task> task,bool is_value = true);
    ~Result() = default;
    //获取任务的返回结果
    void setAny(Any any);
    //将返回结果any_传递给调用者
    Any get();
private:
    Any any_;       //存储任务的 返回值
    Semapthore sempth_;     //线程通信的信号量
    std::shared_ptr<Task> task_;     //指向获取任务的线程对象
    std::atomic_bool is_value_;     //记录中间结果是否出错。
};
//线程任务抽象基类
class Task
{
public:
    Task()
    :result_(nullptr)
    {

    }
    void setResult(Result* res);
    void exec();
    virtual ~Task(){}
    virtual Any run() = 0;
private:
    Result* result_;
};

enum ThreadPoolModel
{
    MODEL_FIXED,        //固定数量线程
    MODEL_CACHEED,      //线程可动态增长
};

//线程类
class Thread
{
private:
    using Func = std::function<void(int)>;
    Func func_;
    int thread_id_;
    static int thread_count_num_;
public:
    Thread(Func func);
    ~Thread();
    void start();
    int getThreadId()const;
};

//线程池类
class ThreadPool
{
private:
    //std::vector<std::unique_ptr<Thread>> threads_;      //线程数组
    std::unordered_map<int,std::unique_ptr<Thread>> threads_;       //线程哈希
    size_t init_threadpool_size_;       //线程初始个数
    std::atomic_int cur_thread_size_;   //当前线程数量
    std::atomic_int idle_threads_;      //空闲线程数量
    size_t max_thread_size_;    //线程池内最大线程个数
    std::atomic_bool is_runing_;    //是否正常执行

    std::queue<std::shared_ptr<Task>> task_que_;      //任务队列，父类指针指向子类对象多态，防止调用者析构了子类对象，这里才去shared_ptr进行指向。
    std::atomic_uint task_que_size_;        //任务队列的任务数量，为了线程安全采用原子变量
    size_t task_que_max_;       //任务队列的上限
    std::mutex task_que_mtx_;       //任务队列的锁

    std::condition_variable not_full_;       //表示任务队列不满；
    std::condition_variable not_empty_;     //表示任务队列不空
    std::condition_variable exit_;  //线程池任务退出通知

    ThreadPoolModel thread_pool_model;      //线程池模式
    std::atomic_bool is_start_;         //线程池是否启动

public:
    ThreadPool(/* args */);
    ~ThreadPool();

    ThreadPool(const ThreadPool&) = delete;
    ThreadPool& operator=(const ThreadPool&) = delete;

    //线程执行函数
    void ThreadFunc(int thread_id);
    
    //设置线程池模式
    void SetThreadPoolModel(ThreadPoolModel threadpool_model);
    // 设置线程池内线程上限
    void SetThreadPoolThreadMax(size_t max_size);
    //设置任务队列上限
    void SetTaskQueMaxThreashhold(size_t task_que_max);
    //往任务队列里插入任务
    Result SubmitTask(std::shared_ptr<Task> task);
    //开启线程池
    void start(size_t init_threadpool_size);
};





#endif